package com.cloorc.example.cloud.consumer;

import com.cloorc.example.clouds.api.ProviderV1Api;
import com.cloorc.example.clouds.api.WhereWho;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriTemplateHandler;
import org.springframework.web.util.UriTemplateHandler;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * First implementation of ConsumerApplication by z0228 on 6/30/17
 *
 * @author : z0228
 * @version : 1.0.0
 * @since : 1.8
 */
@SpringCloudApplication
@EnableEurekaClient
@EnableHystrix
@EnableCircuitBreaker
@RestController
@Import({/*ClientAutoConfiguration.class, */WebClientAutoConfiguration.class})
@EnableFeignClients(clients = {FeignRemote.class})
public class ConsumerApplication {

    @Autowired
    public ConsumerApplication(RestTemplateBuilder builder, LoadBalancerClient client, ProviderV1Api providerV1Api, FeignRemote remote) {
        this.template = builder.build();
        this.providerV1Api = providerV1Api;
        this.remote = remote;
        final UriTemplateHandler handler = this.template.getUriTemplateHandler();
        if (handler instanceof DefaultUriTemplateHandler)
            ((DefaultUriTemplateHandler) handler).setStrictEncoding(true);
        this.client = client;
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(ConsumerApplication.class).web(true).run(args);
    }

    private final RestTemplate template;
    private final LoadBalancerClient client;
    private final ProviderV1Api providerV1Api;
    private final FeignRemote remote;

    @HystrixCommand(fallbackMethod = "fallback")
    @RequestMapping(value = "/hello", params = {"who"})
    public Object hello(@RequestParam(required = false) String who) throws IOException {
        return client.execute("provider", instance ->
            template.getForObject(instance.getUri().toString() + "/hello?who=" + who, Object.class));
    }

    @RequestMapping(value = "/hello-feign", params = {"who"}, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Object helloFeign(@RequestParam(required = false) String who) throws IOException {
        ResponseEntity<List<String>> resp = providerV1Api.hello(new WhereWho(
            new com.cloorc.example.clouds.api.Who(who, 24),
            new com.cloorc.example.clouds.api.Where("Hangzhou")));
        return resp.getBody().get(0);
    }

    @RequestMapping(value = "/hello-YApi", params = {"who"}, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Object helloYApi(@RequestParam(required = false) String who) throws IOException {
        return remote.hello(new WhereWho(
            new com.cloorc.example.clouds.api.Who(who, 24),
            new com.cloorc.example.clouds.api.Where("Hangzhou")));
    }

    public Object fallback(String who) {
        return Collections.singletonMap("msg", who);
    }
}
